Warn when crates.io sends back invalid category slugs
authorCarol (Nichols || Goulding) <carol.nichols@gmail.com>
Tue, 29 Nov 2016 18:19:07 +0000 (13:19 -0500)
committerCarol (Nichols || Goulding) <carol.nichols@gmail.com>
Sat, 3 Dec 2016 16:12:52 +0000 (11:12 -0500)
src/cargo/ops/registry.rs
src/crates-io/lib.rs

index af80760b63bdaf85abca3ba0d131b32845053e80..2b4447609591c7a5eb905fb579f2971a00434567 100644 (file)
@@ -133,7 +133,7 @@ fn transmit(config: &Config,
         return Ok(());
     }
 
-    registry.publish(&NewCrate {
+    let publish = registry.publish(&NewCrate {
         name: pkg.name().to_string(),
         vers: pkg.version().to_string(),
         deps: deps,
@@ -148,9 +148,22 @@ fn transmit(config: &Config,
         repository: repository.clone(),
         license: license.clone(),
         license_file: license_file.clone(),
-    }, tarball).map_err(|e| {
-        human(e.to_string())
-    })
+    }, tarball);
+
+    match publish {
+        Ok(invalid_categories) => {
+            if !invalid_categories.is_empty() {
+                let msg = format!("\
+                    the following are not valid category slugs and were \
+                    ignored: {}. Please see https://crates.io/category_slugs \
+                    for the list of all category slugs. \
+                    ", invalid_categories.join(", "));
+                config.shell().warn(&msg)?;
+            }
+            Ok(())
+        },
+        Err(e) => Err(human(e.to_string())),
+    }
 }
 
 pub fn registry_configuration(config: &Config) -> CargoResult<RegistryConfig> {
index 4d8d889f3b44ef8a2db2639a973c77917783fa87..12c195edbc5a499aea7f3f689088995d9f7a854f 100644 (file)
@@ -10,7 +10,7 @@ use std::io::{self, Cursor};
 use std::result;
 
 use curl::easy::{Easy, List};
-use rustc_serialize::json;
+use rustc_serialize::json::{self, Json};
 
 use url::percent_encoding::{percent_encode, QUERY_ENCODE_SET};
 
@@ -39,6 +39,7 @@ pub enum Error {
     NotFound,
     JsonEncodeError(json::EncoderError),
     JsonDecodeError(json::DecoderError),
+    JsonParseError(json::ParserError),
 }
 
 impl From<json::EncoderError> for Error {
@@ -53,6 +54,12 @@ impl From<json::DecoderError> for Error {
     }
 }
 
+impl From<json::ParserError> for Error {
+    fn from(err: json::ParserError) -> Error {
+        Error::JsonParseError(err)
+    }
+}
+
 impl From<curl::Error> for Error {
     fn from(err: curl::Error) -> Error {
         Error::Curl(err)
@@ -111,7 +118,6 @@ pub struct User {
 #[derive(RustcDecodable)] struct Users { users: Vec<User> }
 #[derive(RustcDecodable)] struct TotalCrates { total: u32 }
 #[derive(RustcDecodable)] struct Crates { crates: Vec<Crate>, meta: TotalCrates }
-
 impl Registry {
     pub fn new(host: String, token: Option<String>) -> Registry {
         Registry::new_handle(host, token, Easy::new())
@@ -148,7 +154,8 @@ impl Registry {
         Ok(json::decode::<Users>(&body)?.users)
     }
 
-    pub fn publish(&mut self, krate: &NewCrate, tarball: &File) -> Result<()> {
+    pub fn publish(&mut self, krate: &NewCrate, tarball: &File)
+                   -> Result<Vec<String>> {
         let json = json::encode(krate)?;
         // Prepare the body. The format of the upload request is:
         //
@@ -191,10 +198,20 @@ impl Registry {
         headers.append(&format!("Authorization: {}", token))?;
         self.handle.http_headers(headers)?;
 
-        let _body = handle(&mut self.handle, &mut |buf| {
+        let body = handle(&mut self.handle, &mut |buf| {
             body.read(buf).unwrap_or(0)
         })?;
-        Ok(())
+        // Can't derive RustcDecodable because JSON has a key named "crate" :(
+        let response = Json::from_str(&body)?;
+        let invalid_categories: Vec<String> =
+            response
+                .find_path(&["warnings", "invalid_categories"])
+                .and_then(Json::as_array)
+                .map(|x| {
+                    x.iter().flat_map(Json::as_string).map(Into::into).collect()
+                })
+                .unwrap_or_else(Vec::new);
+        Ok(invalid_categories)
     }
 
     pub fn search(&mut self, query: &str, limit: u8) -> Result<(Vec<Crate>, u32)> {
@@ -329,6 +346,7 @@ impl fmt::Display for Error {
             Error::NotFound => write!(f, "cannot find crate"),
             Error::JsonEncodeError(ref e) => write!(f, "json encode error: {}", e),
             Error::JsonDecodeError(ref e) => write!(f, "json decode error: {}", e),
+            Error::JsonParseError(ref e) => write!(f, "json parse error: {}", e),
         }
     }
 }